package com.monas.client.view;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.sql.Types;
import java.util.LinkedList;
import java.util.Map;
import java.util.TreeMap;

import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.SashForm;
import org.eclipse.swt.events.SelectionAdapter;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.layout.FillLayout;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.FileDialog;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableItem;
import org.eclipse.ui.forms.widgets.Section;

import com.monas.client.AbstractMonasViewPart;
import com.monas.client.Activator;
import com.monas.client.database.MonasResourceDatabase;
import com.monas.client.export.CSVFile;
import com.monas.client.export.Excel;
import com.monas.client.export.ExcelPlainTable;
import com.monas.client.export.Renderer;
import com.monas.client.jfree.MonasPieChartComposite;
import com.monas.client.util.Column;
import com.monas.client.util.ProgressExporting;

public class AbstractMonitorView extends AbstractMonasViewPart {

	private static final int LIMIT_HISTORY = 100;

	private static final int COLUMN_DEFAULT_LENGTH = 3;

	private final int startIdx;

	private final String id;

	private Composite body;

	private SashForm vertical;
	private SashForm horizontal;

	private Table table;
	private Table historyTable;

	private MonasPieChartComposite pie;

	private String[] headers = { "Used", "Free" };

	private LinkedList<String[]> lasts = new LinkedList<String[]>();
	private Map<String, LinkedList<String[]>> histories = new TreeMap<String, LinkedList<String[]>>();

	private final String title;

	private final Column[] columns;

	private Column[] detailColumns;
	
	private int mainIndex = 0;

	public AbstractMonitorView(String title, String id, int startIdx,
			Column[] columns) {
		this.title = title;
		this.id = id;
		this.startIdx = startIdx;
		this.columns = columns;

		detailColumns = new Column[columns.length + COLUMN_DEFAULT_LENGTH];
		detailColumns[0] = new Column("No.", Types.INTEGER);
		detailColumns[1] = new Column("Node", Types.VARCHAR);
		detailColumns[2] = new Column("Data Time", Types.VARCHAR);
		for (int i = 0; i < columns.length; i++) {
			detailColumns[i + COLUMN_DEFAULT_LENGTH] = columns[i];
		}
	}

	@Override
	public Image getViewImage() {
		return Activator.getMonitorImage();
	}

	@Override
	public void createPartControl(Composite parent) {
		createForm(parent, title);
		createToolbar();
		createBody();
	}

	private void createBody() {
		body = new Composite(form.getBody(), SWT.NONE);
		body.setLayout(new FillLayout());

		vertical = new SashForm(body, SWT.VERTICAL);
		createMainTable();

		horizontal = new SashForm(vertical, SWT.HORIZONTAL);
		createDynamicChart();
		createHistoryTable();

		vertical.setWeights(new int[] { 1, 2 });
	}

	private void createDynamicChart() {
		Section section = createSection(horizontal, PERCENTAGE_CHART);
		String[] first = lasts.get(0);
		pie = new MonasPieChartComposite(section, first[1], headers);

		String[] values = new String[first.length - startIdx];
		for (int i = startIdx; i < first.length; i++) {
			values[i - startIdx] = first[i];
		}

		pie.createChart(values);
		section.setClient(pie.getComposite());
	}

	private void createMainTable() {
		table = createTable(vertical, LAST_DATA);

		table.addSelectionListener(new SelectionAdapter() {

			@Override
			public void widgetSelected(SelectionEvent e) {

				if (e.item instanceof TableItem) {
					TableItem item = (TableItem) e.item;
					String[] fields = new String[table.getColumnCount()
							- startIdx];
					for (int i = startIdx; i < table.getColumnCount(); i++) {
						String value = item.getText(i);
						int percent = value.indexOf("%");
						if (percent >= 0) {
							value = value.substring(0, percent);
						}
						fields[i - startIdx] = value;
					}

					// refresh chart
					String title = item.getText(1);
					pie.refresh(title, fields);

					// refresh history
					historyTable.removeAll();
					addHistoryTableValues(title);
					historyTable.layout();
					
					// selection index for table
					mainIndex = table.getSelectionIndex();
				}
			}

		});

		createColumns(table);

		createContents();
	}

	private void addHistoryTableValues(String title) {
		for (String[] values : histories.get(title)) {
			TableItem newItem = new TableItem(historyTable, SWT.None);
			newItem.setText(values);
		}
	}

	private void createColumns(Table table) {
		createColumn(table, "No.", 50);
		createColumn(table, "Server", 100);
		createColumn(table, "Date", 200);
		for (Column column : columns) {
			createColumn(table, column.getName(), 100);
		}
	}

	private void createHistoryTable() {
		historyTable = createTable(horizontal, "History");

		createColumns(historyTable);
		createHistoryContents();

		historyTable.addSelectionListener(new SelectionAdapter() {
			@Override
			public void widgetSelected(SelectionEvent e) {
				if (e.item instanceof TableItem) {
					TableItem item = (TableItem) e.item;
					String[] fields = new String[historyTable.getColumnCount()
							- startIdx];
					for (int i = startIdx; i < historyTable.getColumnCount(); i++) {
						String value = item.getText(i);
						int percent = value.indexOf("%");
						if (percent >= 0) {
							value = value.substring(0, percent);
						}
						fields[i - startIdx] = value;
					}

					// refresh chart
					String title = item.getText(1);
					pie.refresh(title, fields);
				}
			}
		});
	}

	private void createContents() {

		// hapus list dulu.
		lasts.clear();

		try {
			MonasResourceDatabase db = MonasResourceDatabase.getInstance();

			Integer count = 1;
			for (Object[] values : db.getLast(id)) {
				String[] fields = new String[values.length + 1];
				fields[0] = count.toString();
				for (int i = 0; i < values.length; i++) {
					fields[i + 1] = values[i].toString();
				}
				lasts.add(fields);
				count++;
			}

		} catch (Exception e) {
			e.printStackTrace();
		}

		for (String[] fields : lasts) {
			TableItem item = new TableItem(table, SWT.None);
			item.setText(fields);
		}
	}

	private void createHistoryContents() {

		// hapus list dulu.
		histories.clear();

		LinkedList<String[]> contents = new LinkedList<String[]>();
		String key = null;
		String firstKey = null;
		try {
			MonasResourceDatabase db = MonasResourceDatabase.getInstance();

			Integer count = 1;
			for (Object[] values : db.getHistory(id, LIMIT_HISTORY)) {
				String[] fields = new String[values.length + 1];

				for (int i = 0; i < values.length; i++) {
					if (i == 0) {
						String newKey = values[0].toString();

						if (key == null) {
							key = values[0].toString();
							firstKey = values[0].toString();
						} else if (!newKey.equals(key)) {
							histories.put(key, contents);
							contents = new LinkedList<String[]>();
							count = 1;
							key = newKey;
						}
					}

					fields[i + 1] = values[i].toString();
				}

				fields[0] = count.toString();
				contents.add(fields);
				count++;
			}

			histories.put(key, contents);

		} catch (Exception e) {
			e.printStackTrace();
		}

		addHistoryTableValues(firstKey);
	}

	public void saveDocuments(String label, Table table, Column[] headers) {
		Shell shell = getSite().getShell();
		FileDialog fileDialog = createFileDialog(label, shell, "*.xls", "*.csv");
		String filename = fileDialog.open();
		if (filename == null) {
			return;
		}

		// menentukan tipe dokumen yang akan di-export.
		File file = new File(filename);
		Renderer render = null;
		if (filename.endsWith(Excel.EXCEL_2003_EXTENSION)) {
			render = new ExcelPlainTable(Excel.EXCEL_2003_EXTENSION);
		} else if (filename.endsWith(CSVFile.EXTENSION)) {
			render = new CSVFile(";");
		}

		// Tambahkan semua record dari tabel.
		for (TableItem item : table.getItems()) {
			Object[] record = new Object[table.getColumnCount()];
			for (int i = 0; i < record.length; i++) {
				record[i] = item.getText(i);
			}
			render.addRecord(record);
		}

		// Tentukan header untuk dokumen.
		render.setHeaders(headers);

		FileOutputStream stream = null;
		try {
			/*
			 * Jalankan proses isi ke tabel.
			 */
			stream = new ProgressExporting(shell, render, new FileOutputStream(
					file)).run();
		} catch (Exception e) {
			String message = "Fail export to " + filename;
			MessageDialog.openError(shell, label, message);
		} finally {
			if (stream != null) {
				try {
					stream.close();
				} catch (IOException e) {
					throw new RuntimeException("Fail closing stream", e);
				}
			}
		}
	}

	private FileDialog createFileDialog(String label, Shell shell,
			String... filters) {
		FileDialog fileDialog = new FileDialog(shell, SWT.SAVE);
		fileDialog.setText(label);
		fileDialog.setFilterPath("C:/");
		fileDialog.setFilterExtensions(filters);
		return fileDialog;
	}

	@Override
	public void refresh() {
		// refresh data dari last table
		table.removeAll();
		createContents();
		table.layout();
		table.setSelection(mainIndex);

		// refresh data dari history table
		historyTable.removeAll();
		createHistoryContents();
		historyTable.layout();

	}

	public void saveLastDocuments() {
		saveDocuments("Save Last Document", table, detailColumns);
	}

	public void saveHistoryDocuments() {
		saveDocuments("Save History Document", historyTable, detailColumns);
	}

	public void saveChart() {
		String label = "Save Chart";
		Shell shell = getSite().getShell();
		FileDialog fileDialog = createFileDialog(label, shell, "*.png", "*.jpg");
		String filename = fileDialog.open();
		if (filename == null) {
			return;
		}

		try {
			if (filename.endsWith(".png")) {
				pie.getChart().saveChartIntoPNG(filename);
			} else if (filename.endsWith(".jpg")) {
				pie.getChart().saveChartIntoJPEG(filename);
			}
		} catch (Exception e) {
			String message = "Fail save chart into " + filename;
			MessageDialog.openError(shell, label, message);
		}
	}
}
